package org.one.stone.soup.grfxML.plugin.entityModeler;

import java.io.File;
import java.util.Hashtable;
import java.util.Vector;

import org.one.stone.soup.file.FileHelper;
import org.one.stone.soup.grfxML.DataActionPlugin;
import org.one.stone.soup.grfxML.DataChildren;
import org.one.stone.soup.grfxML.DataNode;
import org.one.stone.soup.grfxML.DataPlugin;
import org.one.stone.soup.grfxML.DataPoint;
import org.one.stone.soup.grfxML.DataString;
import org.one.stone.soup.grfxML.DataText;
import org.one.stone.soup.grfxML.GrfxMLEngine;
import org.one.stone.soup.grfxML.plugin.SimplePlugin;
import org.one.stone.soup.mjdb.data.field.DataLinker;
import org.one.stone.soup.mjdb.data.field.Field;
import org.one.stone.soup.xml.XmlDocument;
import org.one.stone.soup.xml.XmlElement;
import org.one.stone.soup.xml.XmlParseException;
import org.one.stone.soup.xml.XmlParser;
import org.one.stone.soup.xml.stream.XmlLoader;

/**
 * @author nikcross
 *
 * To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Generation - Code and Comments
 */
public class EntityModeler extends SimplePlugin {
	/* (non-Javadoc)
	 * @see org.one.stone.soup.grfxML.DataPlugin#initialize()
	 */
	private boolean initialized = false;
	private String fileName = "untitled.emodel";
	private XmlDocument model;

	private Vector entityVector;
	private Vector associationVector;

	private int processCount=0;

	private GrfxMLEngine engine;

	public EntityModeler(GrfxMLEngine engine)
	{
		super(engine);
		this.engine = engine;
	}

	public void initialize() {
	}

	public XmlElement loadModel( String fileName )
	{
		this.fileName = fileName;

		if( new File(fileName).exists() )
		{
			model = XmlLoader.load(fileName);
			buildModel();
		}
		else
		{
			model = new XmlDocument("model");
		}

		initialized = true;

		return model;
	}

	public void saveModel()
	{
		model = new XmlDocument("model");

		DataChildren parent = (DataChildren)engine.getAPI().getField("layer2");
		try{
			XmlParser parser = engine.getAPI().getXMLParser();

			for(int loop=0;loop<parent.size();loop++)
			{
				DataNode node = parent.get(loop);
				String prototypeName = node.getPrototypeName();
				if(prototypeName==null)
				{
					continue;
				}
				String id = node.getId();

				XmlElement entity = model.addChild("entity");
				XmlElement view = entity.addChild("view");
				view.addAttribute("id",id);
				view.addAttribute("prototype",prototypeName);
				XmlElement defData = view.addChild("data");

				DataPoint position = (DataPoint)engine.getAPI().getField(id+".position");
				XmlElement xPosition = new XmlElement("point");
				xPosition.addAttribute("id","position");
				xPosition.addAttribute("x",""+position.getValueX());
				xPosition.addAttribute("y",""+position.getValueY());
				defData.addChild(xPosition);

				DataText name = (DataText)engine.getAPI().getField(id+".name.value");
				XmlElement xName = parser.parseElement( name.togrfxML("text") );
				xName.setAttributeValue("id","name.value");

				DataText data = (DataText)engine.getAPI().getField(id+".data.value");
				XmlElement xData = parser.parseElement( data.togrfxML("text") );
				xData.setAttributeValue("id","data.value");

				DataText methods = (DataText)engine.getAPI().getField(id+".methods.value");
				XmlElement xMethods = parser.parseElement( methods.togrfxML("text") );
				xMethods.setAttributeValue("id","methods.value");

				defData.addChild(xName);
				defData.addChild(xData);
				defData.addChild(xMethods);
			}

		}catch(XmlParseException xe)
		{
			xe.printStackTrace();
		}

		parent = (DataChildren)engine.getAPI().getField("layer1");

		for(int loop=0;loop<parent.size();loop++)
		{
			DataNode node = parent.get(loop);
			String prototypeName = node.getPrototypeName();
			if(prototypeName==null)
			{
				continue;
			}
			String id = node.getId();

			XmlElement entity = model.addChild("association");
			XmlElement view = entity.addChild("view");
			view.addAttribute("id",id);
			view.addAttribute("prototype",prototypeName);
			XmlElement defData = view.addChild("data");

			DataPoint position = (DataPoint)engine.getAPI().getField(id+".start");
			XmlElement xPosition = new XmlElement("point");
			xPosition.addAttribute("id","start");
			xPosition.addAttribute("x",""+position.getValueX());
			xPosition.addAttribute("y",""+position.getValueY());
			defData.addChild(xPosition);

			position = (DataPoint)engine.getAPI().getField(id+".end");
			xPosition = new XmlElement("point");
			xPosition.addAttribute("id","end");
			xPosition.addAttribute("x",""+position.getValueX());
			xPosition.addAttribute("y",""+position.getValueY());
			defData.addChild(xPosition);

			DataText label = (DataText)engine.getAPI().getField(id+".label.value");
			XmlElement xLabel = new XmlElement("label");
			for(int loopS=0;loopS<label.size();loopS++)
			{
				xLabel.addValue( label.get(loopS).getValue() );
			}
			entity.addChild(xLabel);

		}
	FileHelper.buildFile(fileName,model.toXml().getBytes());

	}

	private void buildModel()
	{
		engine.getAPI().setAutoCommit(false);

		entityVector = new Vector();
		Hashtable distinct = new Hashtable();
		Vector entities = model.getElementsByName("entity");
		DataChildren parent = (DataChildren)engine.getAPI().getField( "layer2" );
		for(int loop=0;loop<entities.size();loop++)
		{
			XmlElement entity = (XmlElement)entities.elementAt(loop);
			XmlElement view = entity.getElementByName("view");
			XmlElement position = view.getElementByName("data").getElementByName("point");

			if( distinct.get(position.toString())!=null)
			{
				continue;
			}
			distinct.put(position.toString(),view);

			DataNode newNode = new DataNode(engine);
			newNode.buildFromgrfxML(view);

			engine.getAPI().add(newNode,parent);

			entityVector.addElement(newNode.getId());
		}

		associationVector = new Vector();
		distinct = new Hashtable();
		entities = model.getElementsByName("association");
		parent = (DataChildren)engine.getAPI().getField( "layer1" );
		for(int loop=0;loop<entities.size();loop++)
		{
			XmlElement entity = (XmlElement)entities.elementAt(loop);
			XmlElement view = entity.getElementByName("view");
			XmlElement position = view.getElementByName("data").getElementByName("point");

			if( distinct.get(position.toString())!=null)
			{
				continue;
			}
			distinct.put(position.toString(),view);

			DataNode newNode = new DataNode(engine);
			newNode.buildFromgrfxML(view);

			engine.getAPI().add(newNode,parent);

			XmlElement label = entity.getElementByName("label");
			DataText text = (DataText)engine.getAPI().getField(newNode.getId()+".label.value");
			try{
				text.setEmpty();
				for(int loopS=0;loopS<label.getElementCount();loopS++)
				{
					text.add(new DataString(label.getData(loopS).toString()) ,this);
				}
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}

			associationVector.addElement(newNode.getId());
		}

		engine.getAPI().commit();

	}

	private void connectEntities()
	{
		if(true)
		{
			return;
		}

	 try{
		for(int loop=0;loop<associationVector.size();loop++)
		{
			String assocId = associationVector.elementAt(loop).toString();

			DataNode association = (DataNode)engine.getAPI().getField(assocId);
			DataPoint start = (DataPoint)engine.getAPI().getField(assocId+".start");
			DataPoint end = (DataPoint)engine.getAPI().getField(assocId+".end");
			DataPlugin arrow = ((DataActionPlugin)association.getProcess().get(0)).getPlugin();

			int startX=start.getValueX();
			int startY=start.getValueY();
			int endX=end.getValueX();
			int endY=end.getValueY();

			for(int loopE=0;loopE<entityVector.size();loopE++)
			{
				String entityId = entityVector.elementAt(loopE).toString();

				DataNode entity = (DataNode)engine.getAPI().getField(entityId);
				DataPoint position = entity.getTranslation().getPosition();
				DataPoint bounds = entity.getBounds();

				int xMin=position.getValueX();
				int yMin=position.getValueY();
				int xMax=xMin+bounds.getValueX();
				int yMax=yMin+bounds.getValueY();

				if(
					startX>=xMin && startX<=xMax &&
					startY>=yMin && startY<=yMax
				)
				{
					association.replace(start,position,true);
					arrow.replace(start,position,true);
					arrow.process();
				}
				if(
					endX>=xMin && endX<=xMax &&
					endY>=yMin && endY<=yMax
				)
				{
					association.replace(end,position,true);
					arrow.replace(end,position,true);
					arrow.process();
				}
			}
		}
	 } catch(NullPointerException ne)
	 {
	 	ne.printStackTrace();
	 }
	}
	/* (non-Javadoc)
	 * @see org.one.stone.soup.mjdb.data.field.Field#register(org.one.stone.soup.mjdb.data.field.DataLinker)
	 */
	public void register(DataLinker store) {
		// TODO Auto-generated method stub
	}
	/* (non-Javadoc)
	 * @see org.one.stone.soup.mjdb.data.field.Field#replace(org.one.stone.soup.mjdb.data.field.Field, org.one.stone.soup.mjdb.data.field.Field)
	 */
	public void replace(Field oldObj, Field newObj) {
		// TODO Auto-generated method stub
	}
	/* (non-Javadoc)
	 * @see org.one.stone.soup.grfxML.DataPlugin#stop()
	 */
	public void stop() {
		saveModel();
	}
	/* (non-Javadoc)
	 * @see org.one.stone.soup.grfxML.Plugin#process()
	 */
	public void process() {

		if( !initialized )
		{
			return;
		}

		if(processCount==1 || processCount%10==0)
		{
			connectEntities();
		}
		processCount++;
	}

	public void finalize()
	{
		//saveModel();
	}
}
